package com.kly.sc.api.application.controller.im;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.google.common.base.Splitter;
import com.kly.sc.api.application.annos.SignIgnore;
import com.kly.sc.api.application.annos.UserBenefitControl;
import com.kly.sc.api.application.annos.VisitorAccessible;
import com.kly.sc.api.application.constant.ApiRedisKeys;
import com.kly.sc.api.application.consts.Constants;
import com.kly.sc.api.application.controller.im.request.ReceiveMessageRequest;
import com.kly.sc.api.application.controller.im.request.ReceiveStatusRequest;
import com.kly.sc.api.application.controller.im.request.SendMessageReq;
import com.kly.sc.api.application.controller.im.request.SendMessageRequest;
import com.kly.sc.api.application.controller.user.request.DoUserLikeRequest;
import com.kly.sc.api.application.enums.ApiResultStatus;
import com.kly.sc.api.application.enums.MsgType;
import com.kly.sc.api.application.helper.RequestLocalInfo;
import com.kly.sc.api.application.service.utils.BaseComponent;
import com.kly.sc.api.application.utils.RpcUtils;
import com.kly.sc.api.infras.enums.RestCodeEnum;
import com.kly.sc.api.infras.exception.ApplicationException;
import com.kly.sc.api.integration.IMService;
import com.kly.sc.api.integration.RCClient;
import com.kly.user.chatterService.ChatService;
import com.kly.user.constant.RedisKey;
import com.kly.user.dto.AddMessageReq;
import com.kly.user.dto.AddWlmReq;
import com.kly.user.dto.UserInfoDto;
import com.kly.user.dto.WlmUserDto;
import com.kly.user.dto.chatter.request.ConversationReq;
import com.kly.user.enums.AppEnum;
import com.kly.user.enums.LikeEnum;
import com.kly.user.enums.NewFlag;
import com.kly.user.enums.RememberTime;
import com.kly.user.service.AuthLoginService;
import com.kly.user.service.OtherService;
import com.kly.user.service.UserService;
import com.kly.user.service.WlmService;
import io.rong.messages.TxtMessage;
import io.rong.models.message.PrivateMessage;
import io.rong.models.response.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * IM平台发送信息
 *
 * @author linqu
 */
@RestController
@RequestMapping("/api/im/message")
@Slf4j
public class IMMessageController extends BaseComponent {

    @Resource
    WlmService wlmService;
    @Resource
    RCClient rcClient;
    @Resource
    AuthLoginService authLoginService;
    @Resource
    IMService imService;
    @Resource
    OtherService otherService;
    @Resource
    RedisClient redisClient;
    @Resource
    ChatService chatService;
    @Resource
    UserService userService;

    private static final String FORMAT = "yyyy-MM-dd HH:mm:ss";

    private static final int DEFAULT_INDEX = 1;

    private static final int DEFAULT_MESSAGE_COUNT = 0;

    private static final int USER_VALID_CONVERSATION = 5;

    private static final int USER_DEEP_CONVERSATION = 30;

    private static final int SESSION_MESSAGE_LIMIT = 100;

    public static final long EFFECTIVE_IN_5_MIN = 60 * 5;

    private static final int ONE_DAYS = 1;


    /**
     * 获取融云平台会话token
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/send", method = RequestMethod.POST)
    public Response sendMessage(@RequestBody SendMessageRequest sendMessageRequest) {

        String currentUserCode = getCurrentUserId();

        // 检查当前用户在IM平台是否完成注册
        validateToken(currentUserCode);
        // 检查目标用户在IM平台是否完成注册
        validateToken(sendMessageRequest.getUserCodeFriend());


        final List<WlmUserDto> userRelation = RpcUtils.getResult(wlmService.getUserRelation(currentUserCode, sendMessageRequest.getUserCodeFriend()));
        // 若不存在关系， 自动添加关系
        if (CollectionUtils.isEmpty(userRelation)) {
            makeFriend(currentUserCode, sendMessageRequest.getUserCodeFriend());
        }


        String conversationType = sendMessageRequest.getConversationType();
        String targetId = sendMessageRequest.getUserCodeFriend();
        String objectName = MsgType.fromType(sendMessageRequest.getObjectName()).getType();
        String content = sendMessageRequest.getContent();
        String pushContent = sendMessageRequest.getPushContent();

        sendMessage(currentUserCode, conversationType, targetId, objectName, content, pushContent);

        // 保存一条对方用户的会话（非当前用户）
        final ConversationReq conversationReq = ConversationReq.builder().fromUserCode(currentUserCode).toUserCode(targetId)
                .type(1).source(getApp().getAppCode()).latestTime(new Date()).conversationType(1).build();
        chatService.storageConversation(conversationReq);

        return Response.ok();
    }

    /**
     * 未查询到目标token, 自动完成注册功能
     */
    private String validateToken(String currentUserCode) {
        final String currentUserToken = RpcUtils.getResult(authLoginService.getRongCloudToken(currentUserCode));
        if (StringUtils.isBlank(currentUserToken)) {
            final UserInfoDto userInfoDto = RpcUtils.getResult(userService.getUserByUserCode(currentUserCode));
            if (Objects.nonNull(userInfoDto) && StringUtils.isNotBlank(userInfoDto.getNickName()) && StringUtils.isNotBlank(userInfoDto.getAvatarUrl())) {
                return imService.getToken(currentUserCode, userInfoDto.getNickName(), userInfoDto.getAvatarUrl());
            }
            throw new ApplicationException("Add IM token failed, userCode:" + currentUserCode);
        }
        return currentUserToken;
    }

    private void makeFriend(String currentUserCode, String targetUserCode) {
        AddWlmReq addWlmReq = new AddWlmReq();
        addWlmReq.setLikeType(LikeEnum.NORMAL.getType());
        addWlmReq.setUserCode(currentUserCode);
        addWlmReq.setNewFlag(NewFlag.NEWS.getType());
        addWlmReq.setUserCodeFriend(targetUserCode);
        wlmService.addWlmUser(addWlmReq);
    }


    private String getCurrentUserId() {
        return RequestLocalInfo.getCurrentUser().getUserCode();
    }

    /**
     * 调用Server api发送消息
     */
    public void sendMessage(String currentUserId, String conversationType, String targetId, String objectName, String content, String pushContent) throws ApplicationException {

        ResponseResult responseResult = null;
        if (Constants.CONVERSATION_TYPE_PRIVATE.equals(conversationType)) {
            PrivateMessage privateMessage = new PrivateMessage()
                    .setSenderId(currentUserId)
                    // 是否向发件人客户端同步已发消息。1 表示同步 0，即不同步
                    .setIsIncludeSender(1)
                    .setTargetId(new String[]{targetId})
                    .setObjectName(objectName)
                    .setContent(new TxtMessage(content, ""))
                    .setPushContent(pushContent);
            responseResult = rcClient.sendPrivateMessage(privateMessage);
        }


        if (Objects.isNull(responseResult) || responseResult.getCode() != 200) {
            log.error("Send message by IM exception, resultCode={},errorMessage={}", responseResult.getCode(), responseResult.getErrorMessage());
            throw new ApplicationException(RestCodeEnum.RC_PARAMETER_ERROR + " errorMsg: " + responseResult.getErrorMessage());
        }

    }

    /**
     * 融云平台消息同步, 参数传递方式 ：application/x-www-form-urlencoded
     * 全量消息路由服务支持将单聊、群组、超级群、聊天室、讨论组（废弃）、客服（废弃）的消息数据同步到指定的应用服务器。
     * 当接收到的消息为图片、视频类消息时，如果需要获取图片、视频等文件信息，可通过地址进行下载，融云文件存储有效期为 6 个月。
     */
    @ResponseBody
    @RequestMapping(value = "/receive_message", method = RequestMethod.POST)
    @VisitorAccessible
    @SignIgnore
    public Response receiveMessage(ReceiveMessageRequest receiveMessageRequest) {
        log.info("Receive message, receiveMsg:{}", JSONObject.toJSONString(receiveMessageRequest));

        String msgType;
        switch (receiveMessageRequest.getObjectName()) {
            case "RC:ImgMsg":
                final String content = receiveMessageRequest.getContent();
                if (StringUtils.isNotBlank(content)) {
                    final JSONObject contentJson = JSONObject.parseObject(content);
                    contentJson.put("content", contentJson.getString("imageUri"));
                    receiveMessageRequest.setContent(JSONObject.toJSONString(contentJson));
                }
            case "RC:ImgTextMsg":
                msgType = "imageUri";
                break;
            case "RC:GIFMsg":
                msgType = "remoteUrl";
                break;
            case "RC:SightMsg":
                final String content1 = receiveMessageRequest.getContent();
                if (StringUtils.isNotBlank(content1)) {
                    final JSONObject contentJson1 = JSONObject.parseObject(content1);
                    contentJson1.put("content", contentJson1.getString("sightUrl"));
                    receiveMessageRequest.setContent(JSONObject.toJSONString(contentJson1));
                }
                msgType = "sightUrl";
                break;
            default:
                msgType = null;

        }
        if (msgType != null) {
            JSONObject content = JSONObject.parseObject(receiveMessageRequest.getContent());
            String msgUrl = content.getString(msgType);
            String dateTime = DateUtil.format(DateUtil.offsetDay(new Date(), ONE_DAYS), FORMAT);
            //添加未查看图片记录
            redisClient.hPut(ApiRedisKeys.NOT_VIEWED_PRIVATE_ALBUM.getValue(),
                    msgUrl, dateTime, receiveMessageRequest.getFromUserId(), receiveMessageRequest.getToUserId());
            //设置过期时间为1天
            redisClient.expire(ApiRedisKeys.NOT_VIEWED_PRIVATE_ALBUM.getValue(), (int) RememberTime.ONE_DAY.getTime(),
                    receiveMessageRequest.getFromUserId(), receiveMessageRequest.getToUserId());
        }


        try {
            AddMessageReq addMessageReq = AddMessageReq.builder().build();

            BeanUtils.copyProperties(receiveMessageRequest, addMessageReq);
            Long timestamp = RequestLocalInfo.getRequestBasicInfo().getTimestamp();
            if (timestamp!=null){
                addMessageReq.setMsgTimestamp(String.valueOf(timestamp));
            }
            otherService.addMessage(addMessageReq);

            return Response.ok();
        } catch (Exception e) {
            log.error("Receive message failed, receiveMsg:{}", JSONObject.toJSONString(receiveMessageRequest), e);
        }
        return Response.ok();
    }

    /**
     * 同步融云平台用户状态, 参数传递方式： application/json
     */
    @ResponseBody
    @RequestMapping(value = "/receive_status", method = RequestMethod.POST)
    @VisitorAccessible
    @SignIgnore
    public Response receiveStatus(@RequestBody List<ReceiveStatusRequest> userStatusList) {
        log.info("Receive user status, receiveMsg:{}", JSONObject.toJSONString(userStatusList));

        try {
            System.out.println("接收到的用户状态：" + JSONObject.toJSONString(userStatusList));
        } catch (Exception e) {
            log.error("Receive user status failed, receiveMsg:{}", JSONObject.toJSONString(userStatusList), e);
        }
        return Response.ok();
    }

    @UserBenefitControl(benefit = "conversations")
    @RequestMapping(value = "/tryToSend", method = RequestMethod.POST)
    public Response tryToSend(@RequestBody ReceiveMessageRequest receiveMessageRequest) {
//        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
//
//        MemberDto memberDto = baseComponent.retrieveMemberFromCacheOrService(userCode);
//        boolean isMember = Optional.ofNullable(memberDto).isPresent();
//        //如果是会员则记录消息条数
//        if (isMember) {
//            // 获取当前会话的消息数量
//            int messageCount = Optional.ofNullable(redisService.getString(
//                            ApiRedisKeys.USER_CONVERSATION_MESSAGE.getValue(), userCode, receiveMessageRequest.getToUserId()))
//                    .map(Integer::parseInt)
//                    .orElseGet(() -> {
//                        List<UserMsgDto> userMsg =
//                                userMsgService.selectByFromUserAndToUser(
//                                        userCode, receiveMessageRequest.getToUserId(), DEFAULT_INDEX);
//                        return (userMsg == null || userMsg.isEmpty()) ?
//                                DEFAULT_MESSAGE_COUNT : userMsg.get(DEFAULT_MESSAGE_COUNT).getId().intValue();
//                    });
//
//            ConversationType fromType = ConversationType.fromType(messageCount);
//            if (fromType != null) {
//                CompletableFuture.runAsync(() -> {
//                    UserConversationRecordDto conversationRecord =
//                            UserConversationRecordDto.builder().userCode(userCode)
//                                    .toUserCode(receiveMessageRequest.getToUserId())
//                                    .conversationsAttributes(ConversationType.EFFECTIVE_CONVERSATIONS.getCode())
//                                    .conversationsType(fromType.getCode())
//                                    .build();
//                    userConversationService.saveUserConversationRecord(conversationRecord);
//                });
//            }
//            redisService.setNumber(ApiRedisKeys.USER_CONVERSATION_MESSAGE.getValue(), (messageCount + DEFAULT_INDEX)
//                    , RememberTime.ONE_DAY.getTime(), userCode, receiveMessageRequest.getToUserId());
//
//        }
        return Response.ok();
    }

    @UserBenefitControl(benefit = "browse")
    @RequestMapping(value = "/tryToBrowse", method = RequestMethod.POST)
    public Response tryToSend(@Valid @RequestBody DoUserLikeRequest doUserLikeRequest, BindingResult results) {
        if (results.hasErrors()) {
            return Response.error(ApiResultStatus.PARAMETER_VALIDATION_FAILED);
        }
        return Response.ok();
    }

    /**
     * 获取融云平台会话token
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/sendMsg", method = RequestMethod.POST)
    @SignIgnore
    public Response sendMessageWithNoToken(@RequestBody SendMessageReq sendMessageReq) {

        // 检查当前用户在IM平台是否完成注册
        validateToken(sendMessageReq.getFromUserCode());
        // 检查目标用户在IM平台是否完成注册
        validateToken(sendMessageReq.getToUserCode());

        String targetId = sendMessageReq.getToUserCode();
        String objectName = MsgType.TxtMsg.getType();
        String content = sendMessageReq.getContent();
        String lastMsg = null;
        if (StringUtils.isNotBlank(content)) {
            List<String> contents = Splitter.on("|").splitToList(content);
            if (contents.size() > 2) {
                contents = contents.subList(0, 2);
            }

            // 已经发送过，不需要再次发送flashchat消息
            final Object sessionId = redisClient.get(RedisKey.FLASH_CHAT_SEND, sendMessageReq.getFromUserCode(), sendMessageReq.getToUserCode());
            if (Objects.nonNull(sessionId)) {
                return Response.ok();
            }

            for (String msg : contents) {
                sendMessage(sendMessageReq.getFromUserCode(), "PRIVATE", targetId, objectName, msg, "");
                lastMsg = msg;
            }

            // 发之前设置redis锁定值，避免http调用超时，重复发送消息
            redisClient.set(RedisKey.FLASH_CHAT_SEND, SecureUtil.md5(sendMessageReq.getFromUserCode() + sendMessageReq.getToUserCode()), EFFECTIVE_IN_5_MIN, sendMessageReq.getFromUserCode(), sendMessageReq.getToUserCode());



        }

        // 保存一条对方用户的会话（非当前用户）
        final ConversationReq conversationReq = ConversationReq.builder().fromUserCode(sendMessageReq.getFromUserCode()).toUserCode(targetId)
                .type(1).source(AppEnum.MECHAT.getAppCode()).latestMsg(lastMsg).latestTime(new Date()).conversationType(1).build();
        chatService.storageConversation(conversationReq);

        return Response.ok();
    }
}
